{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# nuts and bolts\n",
    "\n",
    "*<<< check out other demo models [here](https://github.com/FullControlXYZ/fullcontrol/tree/master/models/README.md) >>>*\n",
    "  \n",
    "run all cells in this notebook, or press shift+enter to run each cell sequentially \n",
    "\n",
    "if you change one of the code cells, make sure you run it and all subsequent cells again (in order)\n",
    "\n",
    "*this document is a jupyter notebook - if they're new to you, check out how they work: [link](https://www.google.com/search?q=ipynb+tutorial), [link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb), [link](https://colab.research.google.com/)*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import fullcontrol as fc\n",
    "from math import tau\n",
    "import lab.fullcontrol as fclab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# printer/gcode parameters\n",
    "\n",
    "design_name = 'nuts_and_bolts'\n",
    "nozzle_temp = 210\n",
    "bed_temp = 40\n",
    "print_speed = 1000\n",
    "fan_percent = 100\n",
    "printer_name='prusa_i3' # generic / ultimaker2plus / prusa_i3 / ender_3 / cr_10 / bambulab_x1 / toolchanger_T0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# design parameters\n",
    "\n",
    "part_type = 'wing_bolt'  # wing_nut / wing_bolt / threaded_tube\n",
    "dia_major, dia_minor, pitch = 8.0, 6.75, 1.25     # M6: 6.0, 5.0, 1.0 / M8: 8.0, 6.75, 1.25 / M10: 10.0, 8.5, 1.5 / M12: 12.0, 10.25, 1.75\n",
    "bolt_or_tube_thread_length = 20 # ignored for wing_nut part_type\n",
    "wing_height = 0.75 * dia_major  # ignored for threaded_tube part_types\n",
    "clearance = 0.1 # this is the amount to undersize male threads or oversize female threads. if you 3D print both male and female threads, the clearance will effectively be doubled\n",
    "EH = 0.15 # extrusion height (layer height is set to this value)\n",
    "EW = 0.6 # extrusion width; recommended to be 1.5*nozzle_diameter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create design steps\n",
    "\n",
    "thread_type = 'female' if part_type == 'wing_nut' else 'male'\n",
    "wing_layers = int((wing_height)/EH)\n",
    "thread_layers = int((bolt_or_tube_thread_length)/EH) \n",
    "if part_type == 'wing_nut': layers = wing_layers\n",
    "if part_type == 'wing_bolt': layers = wing_layers + thread_layers\n",
    "if part_type == 'threaded_tube': layers = thread_layers\n",
    "offset = EW/2+clearance\n",
    "rad_min = (dia_minor/2)-offset if thread_type == 'male' else (dia_minor/2)+offset\n",
    "rad_max = (dia_major/2)-offset if thread_type == 'male' else (dia_major/2)+offset\n",
    "segs = 64  # segments per layer\n",
    "a_shift = ((EH/segs)/pitch)*tau\n",
    "\n",
    "steps = []\n",
    "for i in range(layers):\n",
    "    # print one layer of the thread \n",
    "    for j in range(segs):\n",
    "        z_now = (i+(j/segs))*EH    \n",
    "        a_max = (i*segs+j)*a_shift % tau\n",
    "        a_now = (j/segs)*tau\n",
    "        r_fraction_of_max = 1 - min(abs(a_now - a_max), abs(a_now - (a_max-tau)), abs(a_max - (a_now-tau)))/(tau/2)\n",
    "        r_now = rad_min + r_fraction_of_max * (rad_max-rad_min)\n",
    "        steps.append(fc.polar_to_point(fc.Point(x=0, y=0, z=z_now), r_now, a_now))\n",
    "    # print one layer of the wings for wing-nut or wing-bolt part_types\n",
    "    if part_type == 'wing_nut' or (part_type == 'wing_bolt' and i < wing_layers):\n",
    "        centre_now = fc.Point(x=0, y=0, z=z_now)\n",
    "        bezier_control_pts_1 = fc.rectangleXY(fc.polar_to_point(centre_now, rad_max+EW/4, 0), -(rad_max+EW/4)*2, dia_major*0.4, cw=True)[0:4]\n",
    "        bezier_control_pts_1.insert(2, fc.Point(x=0, y=dia_major*2.25, z=z_now))\n",
    "        steps.extend(fclab.bezierXYdiscrete(bezier_control_pts_1, 32))\n",
    "        bezier_control_pts_2 = fc.move_polar(bezier_control_pts_1, centre_now, 0,tau/2)\n",
    "        steps.extend(fclab.bezierXYdiscrete(bezier_control_pts_2, 32))\n",
    "    # suggested design enhancement: \n",
    "        # repeat the above code for \"print one layer of the thread\" here and adjust r_now by -EW*0.8 to get two-wall print instead of single-wall (with 20% overlap between filament - hence the 0.8)\n",
    "        # or instead of copying the code, an extra for loop around \"for j in range(segs):\" and reduce r_now -EW*0.8*loop_iteration to get as many walls as you like\n",
    "        # or instead of solid reinforcement, design some kind of lattice inside\n",
    "\n",
    "model_offset = fc.Vector(x=50, y=50, z=0.333*EH) # the first layer gradually ramps up - it end at this offset + EH\n",
    "steps = fc.move(steps, model_offset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# preview the design\n",
    "\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(style='line'))\n",
    "# hover the cursor over the lines in the plot to check xyz positions of the points in the design\n",
    "\n",
    "# uncomment the next line to create a plot with real heights/widths for extruded lines to preview the real 3D printed geometry\n",
    "fc.transform(steps, 'plot', fc.PlotControls(zoom=0.5, style='tube', initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n",
    "\n",
    "# uncomment the next line to create a neat preview (click the top-left button in the plot for a .png file) - post and tag @FullControlXYZ :)\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.5,  initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate and save gcode\n",
    "\n",
    "gcode_controls = fc.GcodeControls(\n",
    "    printer_name=printer_name,\n",
    "    save_as=design_name,\n",
    "    initialization_data={\n",
    "        'primer': 'front_lines_then_y',\n",
    "        'print_speed': print_speed,\n",
    "        'nozzle_temp': nozzle_temp,\n",
    "        'bed_temp': bed_temp,\n",
    "        'fan_percent': fan_percent,\n",
    "        'extrusion_width': EW,\n",
    "        'extrusion_height': EH})\n",
    "gcode = fc.transform(steps, 'gcode', gcode_controls)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### please tell us what you're doing with FullControl!\n",
    "\n",
    "- tag FullControlXYZ on social media ([twitter](https://twitter.com/FullControlXYZ), [instagram](https://www.instagram.com/fullcontrolxyz/), [linkedin](https://www.linkedin.com/in/andrew-gleadall-068587119/), [tiktok](https://www.tiktok.com/@fullcontrolxyz))\n",
    "- email [info@fullcontrol.xyz](mailto:info@fullcontrol.xyz)\n",
    "- post on the [subreddit](https://reddit.com/r/fullcontrol)\n",
    "- post in the [github discussions or issues tabs](https://github.com/FullControlXYZ/fullcontrol/issues)\n",
    "\n",
    "in publications, please cite the original FullControl paper and the github repo for the new python version:\n",
    "\n",
    "- Gleadall, A. (2021). FullControl GCode Designer: open-source software for unconstrained design in additive manufacturing. Additive Manufacturing, 46, 102109. \n",
    "- Gleadall, A. and Leas, D. (2023). FullControl [electronic resource: python source code]. available at: https://github.com/FullControlXYZ/fullcontrol"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
